#include "flatbuffer.h"

#include <assert.h>
#include <string.h>

namespace net {

FlatBuffer::FlatBuffer() {
	hold_pos = 0;
	hold_size = 0;
	hold_blank_size = 0;
	total_size = MIN_FLAT_BUFEER_SIZE;

	buf = new char[total_size];

	Init();
}

FlatBuffer::~FlatBuffer() {
	if(buf) {
		delete[] buf;
		buf = NULL;
	}
}

void FlatBuffer::Init() {
	size = 0;
	cur_pos = 0; 
}				

void FlatBuffer::Clean() {
	Init();
}

char* FlatBuffer::GetData() {
	assert(false);
}

uint32_t FlatBuffer::GetSize() {
	return size;
}

void FlatBuffer::Hold() {
	hold_size = size;
	hold_pos = cur_pos;
}

void FlatBuffer::Commit(uint32_t size) {
	uint32_t real_size = size;
	if(size == 0) { //size = 0, 表示整一片内存全部提交
		real_size = this->hold_size;
	}

	if(this->hold_size < real_size) {
		real_size = this->hold_size;
	}

	cur_pos = hold_pos + real_size;
	this->size = hold_size - real_size;

	if(this->size == 0) { 
		Init();
	}
}

void FlatBuffer::Revert() {
	size = hold_size;
	cur_pos = hold_pos;
}

uint32_t FlatBuffer::Read(const char* buf, uint32_t len) {
	if(buf == NULL || len == 0 || size == 0) {
		return 0;
	}

	if(len > size) {
		len = size;
	}

	memcpy((char*)buf, this->buf + cur_pos, len);

	size -= len;
	if(size == 0) { 
		Init();
	}
	else {
		cur_pos += len;
	}
	return len;
}

uint32_t FlatBuffer::Write(const char* buf, uint32_t len) {
	if(buf == NULL || len == 0) {
		return 0;
	}

	if(len <= (total_size - size - cur_pos)) { //剩下的空间可以写下
		Copy((char*)buf, len);
	}
	else {
		if(cur_pos >= len) { //前面空隙的大小可以容纳，需要移动内存
			memmove(this->buf, this->buf + cur_pos, size);
			cur_pos = 0;

			Copy((char*)buf, len);
		}
		else { //内存不够，需要扩容
			Realloc(size + len);				
			Copy((char*)buf, len);
		}
	}

	size += len;
	return len;
}

void FlatBuffer::Realloc(uint32_t len) {
	int real_size = total_size;
	for(int i = 0; i < 99999999; i++) {
			real_size *= 2;	//2倍扩增
			if(real_size >= len) {
				break;
			}
	}

	char* buf = new char[real_size];
	memcpy(buf, this->buf + cur_pos, size);
	delete[] this->buf;

	cur_pos = 0;
	this->buf = buf;
	total_size = real_size;
}

void FlatBuffer::Copy(char* buf, uint32_t len) {
	memcpy(this->buf + cur_pos + size, buf, len);
}

}
